import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class LexicalAnalyzer {

    // 1. 关键字
    static String[] keyword = { "private", "protected", "public", "abstract", "class", "extends",
            "final", "implements", "interface", "native", "new", "static", "strictfp",
            "break", "continue", "return", "do", "while", "if", "else", "for", "instanceof",
            "switch", "case", "default", "boolean", "byte", "char", "double", "float", "int",
            "long", "short", "String", "null", "true", "false", "void", "this", "goto" };

    // 4. 运算符（多个字符的第一个字符都为运算符）
    static String[] operation = { "+", "-", "*", "**", "/", "%", "++", "--", "-=", "*=", "/=", "&", "|",
            "^", "~", "<<", ">>", ">>>", "==", "!=", ">", "<", "=", ">=", "<=", "&&", "||", "!", "." };

    // 5. 界符
    static String[] symbol = { ",", ";", ":", "(", ")", "{", "}" };

    // 当前字符，当前行数
    static int p, line;
    static public char ch;
    static String strToken;
    static String str;

    // 存放关键字、运算符、界符表、常数、标识符
    static List<String> keywords = null;
    static List<String> operations = null;
    static List<String> symbols = null;
    static List<String> constants = null;
    static List<String> ids = null;

    // 主函数
    public static void main(String[] args) {
        // 初始化
        init();
        // 读取txt
        try {
            // 通过字符串创建File类型对象，指向该字符串路径下的文件
            File myFile = new File("src\\main\\resources\\test.txt");
            // 判断文件是否存在
            if (myFile.isFile() && myFile.exists()) {
                InputStreamReader Reader = new InputStreamReader(new FileInputStream(myFile), "UTF-8");
                BufferedReader bufferedReader = new BufferedReader(Reader);
                String lineTxt;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    // bufferReader.readLine()按行读取写成字符串
//                    System.out.println(lineTxt);
                    str = lineTxt;
                    analyzer();
                    line ++;
                }
                Reader.close();
            } else {
                System.out.println("找不到指定的文件");
            }
        } catch (Exception e) {
            System.out.println("读取文件内容出错");
            e.printStackTrace();
        }
    }

    // 初始化
    public static void init() {
        line = 0;
        strToken = "";
        ch = ' ';
        keywords = new ArrayList<>();
        operations = new ArrayList<>();
        symbols = new ArrayList<>();
        constants = new ArrayList<>();
        ids = new ArrayList<>();
    }

    // 词法分析
    public static void analyzer() {
        p = 0;
        str = str.trim();
        str = str + '\0';
        while(p < str.length() - 1) {
            GetChar();
            if(IsDigit()) {
                checkDigit();
            } else if(IsLetter() || ch == '_') {
                Concat();
                GetChar();
                checkLetter();
            } else if (ch == '"') {
                checkString();
            } else if (ch == ' ') {
                GetBC();
            } else if (IsSymbol(String.valueOf(ch))){
                InsertSymbol();
            } else {
                checkOperation();
            }
        }
    }

    // 获取下一个字符
    public static void GetChar() {
        ch = str.charAt(p++);
    }

    // 检测空白
    public static void GetBC() {
        while(ch == ' ') {
            ch = str.charAt(p++);
        }
        Retract();
    }

    // 连接字符
    public static void Concat() {
        strToken = strToken.concat(String.valueOf(ch));
    }

    // 判断是不是字母
    public static boolean IsLetter() {
        return Character.isLetter(ch);
    }

    // 判断是不是数字
    public static boolean IsDigit() {
        return Character.isDigit(ch);
    }

    // 查找关键字表
    public static boolean Reserve() {
        return Arrays.asList(keyword).contains(strToken);
    }

    // 查找界符
    public static boolean IsSymbol(String str) {
        return Arrays.asList(symbol).contains(str);
    }

    // 查找运算符
    public static boolean IsOperation(String str) {
        return Arrays.asList(operation).contains(str);
    }

    // 回调
    public static void Retract() {
        p--;
        ch = ' ';
    }

    // 插入关键字表
    public static void InsertKeyword() {
        keywords.add(strToken);
        System.out.println("( " + 1 + ", " + strToken + " )");
        strToken = "";
    }

    // 插入运算符表
    public static void InsertOperation() {
        operations.add(strToken);
        System.out.println("( " + 4 + ", " + strToken + " )");
        strToken = "";
    }

    // 插入界符表
    public static void InsertSymbol() {
        symbols.add(String.valueOf(ch));
        System.out.println("( " + 5 + ", " + ch + " )");
        strToken = "";
    }

    // 插入常数表
    public static void InsertConstant() {
        constants.add(strToken);
        System.out.println("( " + 3 + ", " + strToken + " )");
        strToken = "";
    }

    // 插入标识符
    public static void InsertId() {
        ids.add(strToken);
        System.out.println("( " + 2 + ", " + strToken + " )");
        strToken = "";
    }

    // 错误提示
    public static void Error() {
        System.out.println("Illegal Argument : " + ch);
    }

    // 得到数字
    public static void checkDigit() {
        boolean flag = true;
        while (IsDigit()) {
            Concat();
            GetChar();
        }
        if (ch == '.') {
            Concat();
            GetChar();
            while (IsDigit()) {
                Concat();
                GetChar();
            }
        }
        while (IsLetter()) {
            flag = false;
            Concat();
            GetChar();
        }
        Retract();
        if (flag) InsertConstant();
        else {
            System.out.println("Illegal Argument:" + strToken);
            strToken = " ";
        }
    }

    // 得到变量
    public static void checkLetter() {
        while(IsDigit() || IsLetter() || ch == '_') {
            Concat();
            GetChar();
        }
        Retract();
        if (Reserve()) {
            InsertKeyword();
        } else {
            InsertId();
        }
    }

    // 检验是否是运算符
    public static void checkOperation() {
        if (IsOperation(String.valueOf(ch))) {
            Concat();
            GetChar();
            while(IsOperation(strToken + ch)) {
                Concat();
                GetChar();
            }
            InsertOperation();
        } else {
            Error();
            GetChar();
        }
        Retract();
    }

    // 检验字符串
    public static void checkString() {
        int res = p;
        boolean flag = false;
        while (p < str.length() - 1) {
            GetChar();
            if (ch == '"') {
                flag = true;
                break;
            }
            Concat();
        }
        if (!flag) {
            p = res;
            Error();
        } else {
            InsertConstant();
        }
        strToken = " ";
    }

}
